const logger = require('./logger');
const { RETRY_POLICY } = require('../config/constants');

class ErrorHandler {
    static async withRetry(operation, options = {}) {
        const { 
            maxRetries = 3,
            initialDelayMs = 1000,
            maxDelayMs = 10000,
            shouldRetry = (err) => true,
            onRetry = (err, attempt, delay) => {}
        } = options;
        
        let lastError;
        for (let attempt = 0; attempt < maxRetries; attempt++) {
            try {
                return await operation();
            } catch (err) {
                lastError = err;
                const errorType = this.classifyError(err);
                logger.error(`操作失败 (尝试 ${attempt+1}/${maxRetries})`, {
                    error: err.message,
                    type: errorType,
                    stack: err.stack
                });
                
                if (!shouldRetry(err)) break;
                if (attempt < maxRetries - 1) {
                    // 指数退避算法
                    const delay = Math.min(
                        initialDelayMs * Math.pow(2, attempt),
                        maxDelayMs
                    );
                    onRetry(err, attempt, delay);
                    await new Promise(res => setTimeout(res, delay));
                }
            }
        }
        
        throw lastError || new Error('未知错误');
    }

    static classifyError(err) {
        if (err.response) {
            if (err.response.status >= 500) return 'server_error';
            if (err.response.status === 429) return 'rate_limit';
            if (err.response.status === 401) return 'auth_error';
            return 'api_error';
        }
        if (err.code === 'ECONNABORTED') return 'timeout';
        if (err.code === 'ENOTFOUND') return 'network_error';
        return 'unknown_error';
    }

    static logError(context, error, metadata = {}) {
        const errorType = this.classifyError(error);
        logger.error(context, {
            error: error.message,
            type: errorType,
            stack: error.stack,
            timestamp: new Date().toISOString(),
            ...metadata
        });
    }
}

module.exports = ErrorHandler;